"""
Blueprint日志更新工具
自动为所有Blueprint的API方法添加日志装饰器
"""
import os
import re
from typing import List, Dict, Tuple


class BlueprintLogUpdater:
    """Blueprint日志更新器"""
    
    def __init__(self, blueprints_dir: str):
        self.blueprints_dir = blueprints_dir
        self.log_imports = [
            "from app.utils.logger import FlinkLogger, log_api_call, log_database_operation",
            "from flask import current_app"
        ]
    
    def get_blueprint_files(self) -> List[str]:
        """获取所有Blueprint文件"""
        blueprint_files = []
        for root, _dirs, files in os.walk(self.blueprints_dir):
            for file in files:
                if file.endswith('.py') and file != '__init__.py' and not file.endswith('.backup'):
                    blueprint_files.append(os.path.join(root, file))
        return blueprint_files
    
    def extract_api_methods(self, content: str) -> List[Dict[str, str]]:
        """提取API方法信息"""
        methods = []
        
        # 匹配Flask路由装饰器和函数定义
        pattern = r'@bp\.(get|post|put|delete|patch)\(["\']([^"\']+)["\']\)\s*\n(?:@[\w_.]+.*\n)*def\s+(\w+)\s*\([^)]*\):'
        matches = re.finditer(pattern, content, re.MULTILINE)
        
        for match in matches:
            http_method = match.group(1)
            route = match.group(2)
            function_name = match.group(3)
            
            methods.append({
                'http_method': http_method.upper(),
                'route': route,
                'function_name': function_name,
                'full_match': match.group(0),
                'start': match.start(),
                'end': match.end()
            })
        
        return methods
    
    def has_log_decorator(self, content: str, function_name: str) -> bool:
        """检查函数是否已有日志装饰器"""
        pattern = rf'@log_api_call\(["\'][^"\']*["\']\)\s*\n(?:@[\w_.]+.*\n)*def\s+{function_name}\s*\([^)]*\):'
        return bool(re.search(pattern, content, re.MULTILINE))
    
    def add_log_decorator(self, content: str, method_info: Dict[str, str]) -> str:
        """为方法添加日志装饰器"""
        function_name = method_info['function_name']
        
        # 如果已有装饰器，跳过
        if self.has_log_decorator(content, function_name):
            return content
        
        # 构建日志装饰器
        blueprint_name = self.get_blueprint_name(content)
        log_operation = f"{blueprint_name}.{function_name}"
        log_decorator = f'@log_api_call("{log_operation}")'
        
        # 找到函数定义位置
        pattern = rf'(@bp\.{method_info["http_method"].lower()}\(["\'][^"\']*["\']\)\s*\n)(def\s+{function_name}\s*\([^)]*\):)'
        
        def replacement(match):
            route_decorator = match.group(1)
            function_def = match.group(2)
            return f"{route_decorator}{log_decorator}\n{function_def}"
        
        updated_content = re.sub(pattern, replacement, content, flags=re.MULTILINE)
        
        # 在函数开始处添加日志记录
        function_pattern = rf'(def\s+{function_name}\s*\([^)]*\):\s*\n)(\s*"""[^"]*"""\s*\n)?'
        
        def add_logging(match):
            func_def = match.group(1)
            docstring = match.group(2) or ""
            
            # 构建日志语句
            log_statement = f'    current_app.logger.info("API Call: {log_operation} started")\n'
            
            return f"{func_def}{docstring}{log_statement}"
        
        updated_content = re.sub(function_pattern, add_logging, updated_content, flags=re.MULTILINE)
        
        return updated_content
    
    def get_blueprint_name(self, content: str) -> str:
        """从内容中提取Blueprint名称"""
        pattern = r'bp\s*=\s*Blueprint\(["\']([^"\']+)["\']\s*,'
        match = re.search(pattern, content)
        return match.group(1) if match else "unknown"
    
    def ensure_imports(self, content: str) -> str:
        """确保必要的导入语句存在"""
        lines = content.split('\n')
        import_section_end = 0
        
        # 找到导入部分的结束位置
        for i, line in enumerate(lines):
            if line.strip().startswith('from ') or line.strip().startswith('import '):
                import_section_end = i + 1
            elif line.strip() and not line.strip().startswith('#'):
                break
        
        # 检查并添加缺失的导入
        existing_imports = '\n'.join(lines[:import_section_end])
        imports_to_add = []
        
        for import_stmt in self.log_imports:
            if import_stmt not in existing_imports:
                # 检查是否有类似的导入需要更新
                if "from app.utils.logger import" in existing_imports and "from app.utils.logger import" in import_stmt:
                    # 更新现有的导入
                    for j, line in enumerate(lines[:import_section_end]):
                        if line.strip().startswith("from app.utils.logger import"):
                            lines[j] = import_stmt
                            break
                elif "from flask import" in existing_imports and "from flask import" in import_stmt:
                    # 更新Flask导入
                    for j, line in enumerate(lines[:import_section_end]):
                        if line.strip().startswith("from flask import") and "current_app" not in line:
                            if not line.strip().endswith(','):
                                lines[j] = line.rstrip() + ", current_app"
                            else:
                                lines[j] = line.rstrip() + " current_app"
                            break
                else:
                    imports_to_add.append(import_stmt)
        
        # 添加新的导入
        if imports_to_add:
            lines[import_section_end:import_section_end] = imports_to_add + ['']
        
        return '\n'.join(lines)
    
    def update_blueprint_file(self, file_path: str) -> Tuple[bool, str]:
        """更新单个Blueprint文件"""
        try:
            with open(file_path, 'r', encoding='utf-8') as f:
                content = f.read()
            
            original_content = content
            
            # 确保导入语句
            content = self.ensure_imports(content)
            
            # 提取API方法
            methods = self.extract_api_methods(content)
            
            # 为每个方法添加日志装饰器
            for method in methods:
                content = self.add_log_decorator(content, method)
            
            # 如果内容有变化，写回文件
            if content != original_content:
                # 创建备份
                backup_path = f"{file_path}.backup"
                with open(backup_path, 'w', encoding='utf-8') as f:
                    f.write(original_content)
                
                # 写入更新后的内容
                with open(file_path, 'w', encoding='utf-8') as f:
                    f.write(content)
                
                return True, f"Updated {len(methods)} methods in {os.path.basename(file_path)}"
            else:
                return False, f"No changes needed for {os.path.basename(file_path)}"
                
        except Exception as e:
            return False, f"Error updating {os.path.basename(file_path)}: {str(e)}"
    
    def update_all_blueprints(self) -> Dict[str, str]:
        """更新所有Blueprint文件"""
        results = {}
        blueprint_files = self.get_blueprint_files()
        
        for file_path in blueprint_files:
            success, message = self.update_blueprint_file(file_path)
            results[os.path.basename(file_path)] = {
                'success': success,
                'message': message
            }
        
        return results
    
    def generate_update_report(self, results: Dict[str, str]) -> str:
        """生成更新报告"""
        report = ["Blueprint日志更新报告", "=" * 50, ""]
        
        updated_files = []
        unchanged_files = []
        error_files = []
        
        for filename, result in results.items():
            if result['success'] and "Updated" in result['message']:
                updated_files.append(f"✅ {filename}: {result['message']}")
            elif result['success']:
                unchanged_files.append(f"➖ {filename}: {result['message']}")
            else:
                error_files.append(f"❌ {filename}: {result['message']}")
        
        if updated_files:
            report.extend(["已更新的文件:", ""] + updated_files + [""])
        
        if unchanged_files:
            report.extend(["无需更新的文件:", ""] + unchanged_files + [""])
        
        if error_files:
            report.extend(["更新失败的文件:", ""] + error_files + [""])
        
        report.extend([
            "",
            "总结:",
            f"- 已更新: {len(updated_files)} 个文件",
            f"- 无需更新: {len(unchanged_files)} 个文件", 
            f"- 更新失败: {len(error_files)} 个文件",
            f"- 总计: {len(results)} 个文件"
        ])
        
        return "\n".join(report)


def main():
    """主函数"""
    import sys
    import os
    
    # 获取Blueprint目录路径
    current_dir = os.path.dirname(os.path.abspath(__file__))
    blueprints_dir = os.path.join(os.path.dirname(current_dir), 'blueprints')
    
    if not os.path.exists(blueprints_dir):
        print(f"Blueprint目录不存在: {blueprints_dir}")
        sys.exit(1)
    
    # 创建更新器并执行更新
    updater = BlueprintLogUpdater(blueprints_dir)
    results = updater.update_all_blueprints()
    
    # 生成并显示报告
    report = updater.generate_update_report(results)
    print(report)
    
    # 保存报告到文件
    report_path = os.path.join(os.path.dirname(blueprints_dir), 'logs', 'blueprint_update_report.txt')
    os.makedirs(os.path.dirname(report_path), exist_ok=True)
    
    with open(report_path, 'w', encoding='utf-8') as f:
        f.write(report)
    
    print(f"\n报告已保存到: {report_path}")


if __name__ == "__main__":
    main()
